package com.vito.oa.act.extend.service.impl;

import static com.vito.oa.act.constant.OaActContants.CACHE_ACT_VALUE;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.vito.act.model.ActExSaveModel;
import com.vito.act.service.impl.ActProgressTableServiceImpl;
import com.vito.act.tool.ActivitiFormDataTool;
import com.vito.act.tool.ActivitiTool;
import com.vito.act.tool.OaActivitiFormDataTool;
import com.vito.base.authoriza.dao.SQLAdapterMapper;
import com.vito.base.authoriza.model.FileModel;
import com.vito.base.authoriza.model.UserModel;
import com.vito.base.authoriza.service.FileService;
import com.vito.base.exception.ParamErrorException;
import com.vito.base.model.FtpModel;
import com.vito.base.model.MyHashMap;
import com.vito.base.model.Result;
import com.vito.base.util.Contants;
import com.vito.base.util.FreeMarkerUtil;
import com.vito.base.util.FtpHelper;
import com.vito.base.util.JSONUtil;
import com.vito.base.util.Pty;
import com.vito.base.util.StringUtil;
import com.vito.base.util.Validata;
import com.vito.oa.act.constant.OaActContants;
import com.vito.oa.act.constant.OaActContants.ProcessButtonEnum;
import com.vito.oa.act.dao.ActSignMapper;
import com.vito.oa.act.dao.ActUserProcessSettingMapper;
import com.vito.oa.act.dao.OaActAbstractMapper;
import com.vito.oa.act.dao.OaActApproverMapper;
import com.vito.oa.act.extend.dao.OaActExBussDefMapper;
import com.vito.oa.act.extend.dao.OaActExDataFollowMapper;
import com.vito.oa.act.extend.dao.OaActExDataMapper;
import com.vito.oa.act.extend.dao.OaActExTableMapper;
import com.vito.oa.act.extend.model.OaActExTableColsModel;
import com.vito.oa.act.extend.service.OaActExTableColsService;
import com.vito.oa.act.extend.service.OaActProgressTableService;
import com.vito.oa.act.model.ActUserNodeSettingModel;
import com.vito.oa.act.model.BusinessApproverModel;
@Service
public class OaActProgressTableServiceImpl  implements OaActProgressTableService {
	@Autowired
	private SQLAdapterMapper sqlAdapterMapper;
	@Autowired
	private OaActExBussDefMapper actExBussDefMapper;
	@Autowired
	private OaActExDataMapper actExDataMapper;
	@Autowired
	private OaActExDataFollowMapper actExDataFollowMapper;
	@Autowired
	private  OaActExTableColsService actExTableColsService;
	@Autowired
	private FileService fileServiceImpl;
	@Autowired
	private OaActApproverMapper oaActApproverMapper;
	@Autowired
	private OaActExTableMapper oaActExTableMapper;
	@Autowired
	private OaActAbstractMapper OaActAbstractMapper;
	@Autowired
	private ActSignMapper sealMapper;
	@Autowired
	private ActUserProcessSettingMapper actUserProcessSettingMapper;

	private static String dialect="oracle";//数据库类型
	static{
		Pty pty  = null;
		try {
			pty = Pty.get("conf/jdbc");
		} catch (Exception e) {
		}
		if(pty!=null){
			dialect = pty.getProp("sql.dialect");
		}
	}
	public int saveProgressTableInfo(UserModel user,Map<String, Map<String, Object>> map,ProcessButtonEnum btn) {
		Map<String, Object> info = (Map<String, Object>)map.get(Contants.FORM_KEY_INFO);
		String key = info.get(Contants.FORM_KEY_KEY)+"";
		String nodeId = info.get(Contants.FORM_KEY_NODEID)+"";
		String action =null;
		if(btn == null){
			ActUserNodeSettingModel setting = actUserProcessSettingMapper.queryNodeSetting(key, user.getDeptParentId(), nodeId);
			if(setting != null){
				action = setting.getMarkOfApproved();
			}
		}else{
			action = btn.nameCh;
		}
		info.put(Contants.FORM_KEY_ACTION, action);
		return saveProgressTableInfo(user, map);
	}
	@SuppressWarnings("unchecked")
	@Override
	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public int saveProgressTableInfo(UserModel user,Map<String, Map<String, Object>> map) {
		//初始化工具类的下标及sql存储map
		ActExSaveModel model = new ActExSaveModel();
		Map<String, Object> info = (Map<String, Object>)map.get(Contants.FORM_KEY_INFO);
		String key = info.get(Contants.FORM_KEY_KEY)+"";
		String nodeId = info.get(Contants.FORM_KEY_NODEID)+"";
		String refKey = oaActExTableMapper.queryRefkey(key,nodeId);
		String businessId = info.get(Contants.FORM_KEY_BUSENESSID)+"";
		String taskId = info.get(Contants.FORM_KEY_TASKID)+"";
		//获取主表信息
		Map<String, Object> main = (Map<String, Object>)map.get(Contants.FORM_KEY_MAIN);

		//首节点主表摘要保存
		if(OaActContants.FORM_PROCESS_START.equals(nodeId) && main != null && !main.isEmpty()){
			String mainTabKey = null;
			Map<String, Object> mainData=null;
			for(Entry<String,Object> mainEntry : main.entrySet()){
				mainTabKey = mainEntry.getKey();
				Map<String, Object> table = (Map<String, Object>)mainEntry.getValue();
				mainData = (Map<String, Object>)table.get(Contants.FORM_KEY_DATA);
				break;
			}
			List<OaActExTableColsModel> abstCol= OaActAbstractMapper.queryAbstractCol(refKey, mainTabKey);
			String abstractStr = getApprovalAbstract(businessId,abstCol,mainData);
			OaActAbstractMapper.saveAbstract(businessId, abstractStr);
		}else{
			//保存印章
			String seal = info.containsKey(OaActContants.NODE_SEAL)?info.get(OaActContants.NODE_SEAL)+"":null;
			if(Validata.notNullOrEmpty(seal)){
				sealMapper.saveApproveSeal(businessId, nodeId, taskId, seal);
			}
			//保存签名
			String sign = info.containsKey(OaActContants.NODE_SIGN)?info.get(OaActContants.NODE_SIGN)+"":null;
			if(Validata.notNullOrEmpty(sign)){
				sealMapper.saveApproveSign(businessId, nodeId, taskId, sign);
			}
		}
		//初始化主表保存sql
		initTableSql(main, true, model, info.get(Contants.FORM_KEY_TASKID)+"",refKey);
		//获取从表信息
		Map<String, Object> subs = (Map<String, Object>)map.get(Contants.FORM_KEY_SUBS);
		//初始化从表保存sql
		initTableSql(subs, false, model, info.get(Contants.FORM_KEY_TASKID)+"",refKey);
		if(model.getSql()!=null&&model.getSql().length()>0){
			model.getParam_map().put("sql", model.getSql().toString());
			model.getParam_map().put("databaseId", dialect);
			sqlAdapterMapper.updateDataBysql(model.getParam_map());
		}
		Map<String, Object> save_map = new HashMap<String, Object>();
		save_map.put("busenessId", businessId);
		save_map.put("processKey", key);
		save_map.put("processNodeId", nodeId);
		save_map.put("taskId", taskId);
		save_map.put("action", info.get(Contants.FORM_KEY_ACTION)+"");
		save_map.put("userId", user.getUserId());
		if(Contants.FORM_PROCESS_MAIN_TASKID.equals(taskId)){
			actExDataMapper.saveActExData(save_map);
		}
		actExDataFollowMapper.saveActExDataFollow(save_map);
		return 1;
	}
	/**
	 * 从提交的数据中提取部门数据作为摘要并返回
	 * @param businessId
	 * @param cols 表单
	 * @param colData 提交的数据
	 * @return 拼接的摘要信息
	 */
	private String getApprovalAbstract(String businessId,List<OaActExTableColsModel> cols,Map<String, Object> colData){
		StringBuilder abstractStr =  new StringBuilder();
		if(cols != null && colData != null){
			String funName = null;
			String colName = null;
			String colVal = null;
			String showType = null;
			int i = 0;
			for(OaActExTableColsModel col : cols){
				//需求最多取4条
				if(i>=4){
					break;
				}
				funName = col.getFunName();
				colName = col.getColName();
				colVal = (String) colData.get(colName);
				showType = col.getShowType();
				//附件不保存
				if(Validata.isNullOrEmpty(colVal) || OaActContants.FORM_SHOWTYPE_FILE.equals(showType)
						|| OaActContants.FORM_SHOWTYPE_HIDDEN.equals(showType)){
					continue;
				}

				if(Validata.notNullOrEmpty(funName)){
					funName = funName.replaceAll("[?]", "'"+colVal+"'");
					String sql = "select "+funName+" from dual";
					colVal = OaActAbstractMapper.getSingelDataBySql(sql);
				}

				abstractStr.append(col.getColNameCh()+"："+colVal+OaActContants.SEPARATOR_VITO);
				i++;
			}
			int lastIndex = abstractStr.lastIndexOf(OaActContants.SEPARATOR_VITO);
			if(lastIndex > -1){
				abstractStr.substring(0, lastIndex);
			}
		}
		return abstractStr.toString();
	}
	@SuppressWarnings("unchecked")
	public void initTableSql(Map<String, Object> map,boolean isMain,ActExSaveModel model,String taskId,String refKey){
		if(map!=null&&!map.isEmpty()){
			String encrypt = "1";
			for(Entry<String, Object> entry:map.entrySet()){
				String tableKey = entry.getKey();
				if(OaActContants.COMM_TABLE_KEY.equals(tableKey)){
					encrypt = oaActExTableMapper.queryTableEncrypt(refKey);
				}else{
					encrypt = oaActExTableMapper.queryTableEncrypt(tableKey);
				}
				Map<String, Object> table = (Map<String, Object>)entry.getValue();
				Map<String,String> tab = new HashMap<String,String>();
				tab.put(OaActContants.FORM_KEY_TABLE_NAME, Contants.TABLE_FIRST_NAME + tableKey);
				tab.put(OaActContants.FORM_KEY_PKNAME, table.get(Contants.FORM_KEY_PKNAME)+"");
				tab.put(OaActContants.FORM_OPER_TYPE, table.get(OaActContants.FORM_OPER_TYPE)+"");
				tab.put(OaActContants.FORM_ENCRYPT, encrypt);
				if(isMain){
					Map<String, Object> data = (Map<String, Object>)table.get(Contants.FORM_KEY_DATA);
					OaActivitiFormDataTool.getInsOrUpdSql(tab, data,taskId,true,model);
				}else{
					tab.put(OaActContants.FORM_KEY_FKNAME, table.get(OaActContants.FORM_KEY_FKNAME)+"");
					List<Map<String, Object>> data = (List<Map<String, Object>>)table.get(Contants.FORM_KEY_DATA);
					if(data!=null&&data.size()>0){
						for (int j = 0; j < data.size(); j++) {
							OaActivitiFormDataTool.getInsOrUpdSql(tab,data.get(j),taskId,false,model);
						}
					}
				}
			}
		}
	}
	@SuppressWarnings("unchecked")
	@Override
	@Cacheable(value = CACHE_ACT_VALUE, key = "#root.method.name+'_'+#processKey+'_'+#processNodeId+'_'+#bussId+'_'+#taskId")
	public MyHashMap<String, Object> queryBussInfo(String processKey,
			String processNodeId,String bussId, String taskId){
		MyHashMap<String, Object> data = queryOriginalBussInfo(processKey, processNodeId, bussId, taskId);
		List<Map<String, Object>> mains = (List<Map<String, Object>>) data.get(Contants.FORM_KEY_MAIN);
		List<Map<String, Object>> subs = (List<Map<String, Object>>) data.get(Contants.FORM_KEY_SUBS);
		if(mains != null){
			for(Map<String, Object> main:mains){
				decryptFormData(main);
			}
		}
		if(subs != null){
			for(Map<String, Object> sub:subs){
				decryptFormData(sub);
			}
		}
		return data;
	}

	/**
	 * 解密表单
	 * @param formData
	 */
	@SuppressWarnings("unchecked")
	private void decryptFormData(Map<String,Object> formData){
		if(formData != null && !formData.isEmpty()){
			OaActivitiFormDataTool.decryptData(formData);
			List<Map<String,String>> cols = (List<Map<String,String>>) formData.get(Contants.FORM_KEY_COLS);
			List<Map<String,Object>> cols_data = (List<Map<String, Object>>) formData.get(Contants.FORM_KEY_DATA);
			MyHashMap<String, Object> addOn = null;
			for(int i = 0;i<cols.size();i++){
				Map<String, String> col = cols.get(i);
				if(Contants.FORM_SHOWTYPE_FILE.equalsIgnoreCase(col.get("showtype"))){
					if(cols_data.get(0) == null){
						continue;
					}
					String path = (String)cols_data.get(0).get(col.get("colname"));
					if(Validata.isNullOrEmpty(path)){
						continue;
					}
					String fileIds[] = path.split(",");
					List<FileModel> fileList = new ArrayList<FileModel>();
					if(fileIds != null && fileIds.length > 0){
						for(String fileId : fileIds ){
							String[] subStr = fileId.split("_");
							String[] subStr2 = subStr[subStr.length-1].split("\\.");
							String id = subStr2[0];
							FileModel fileModel = new FileModel();
							fileModel.setFileId(id);
							List<FileModel> file = fileServiceImpl.queryFile(fileModel);
							if(null!=file && !file.isEmpty()){
								fileList.add(file.get(0));
							}
						}
					}
					if(null!=fileList && !fileList.isEmpty()){
						if(null == addOn){
							addOn = new MyHashMap<String, Object>();
						}
						addOn.put(col.get("colname"), fileList);
					}
				}
			}
			formData.put(Contants.FORM_KEY_DATA_ADDON, addOn);
		}
	}

	/**
	 * 查询原始的节点及表单信息
	 * @param processKey
	 * @param processNodeId
	 * @param bussId
	 * @param taskId
	 * @return
	 */
	private MyHashMap<String, Object> queryOriginalBussInfo(String processKey,
			String processNodeId,String bussId, String taskId){
		Map<String, Object> res = new HashMap<String, Object>();
		List<MyHashMap<String, String>> first_node_tables = actExBussDefMapper.queryProcessNodeTables(processKey, Contants.FORM_PROCESS_START);
		String main_tableName = "";
		for(MyHashMap<String, String> table:first_node_tables){
			//主表
			if(Validata.isNullOrEmpty(table.get("parent_table_key"))){
				main_tableName = table.get("table_key");
				break;
			}
		}
		//根据processKey，processNodeId查询当前节点对应的所有表
		List<MyHashMap<String, String>> tables = actExBussDefMapper.queryProcessNodeTables(processKey, processNodeId);
		if(tables!=null&&tables.size()>0){

			List<MyHashMap<String, Object>> main = new ArrayList<MyHashMap<String,Object>>();
			List<MyHashMap<String, Object>> subs = new ArrayList<MyHashMap<String,Object>>();

			//流程首节点（流程第一步）
			if(Contants.FORM_PROCESS_MAIN_TASKID.equals(taskId)){
				for(MyHashMap<String, String> table:tables){
					//主表
					if(Validata.isNullOrEmpty(table.get("parent_table_key"))){
						initTableData(table, main, bussId, null);
					}
					//从表
					if(!Validata.isNullOrEmpty(table.get("parent_table_key")) && main_tableName.equals(table.get("parent_table_key"))){
						initTableData(table, subs, bussId, taskId);
					}
				}
				//从表
			}else{
				for(MyHashMap<String, String> table:tables){
					//从表
					if(!Validata.isNullOrEmpty(table.get("parent_table_key")) && main_tableName.equals(table.get("parent_table_key"))){
						initTableData(table, subs, bussId, taskId);
					}
				}
			}
			res.put(Contants.FORM_KEY_MAIN, main);
			res.put(Contants.FORM_KEY_SUBS, subs);
		}
		MyHashMap<String, Object> ret = convertHashMapToMyHashMap(res);
		return ret;
	}
	public MyHashMap<String, Object> convertHashMapToMyHashMap(Map<String, Object> map){
		MyHashMap<String, Object> res = new MyHashMap<String,Object>();
		for (String key:map.keySet()) {
			res.put(key, map.get(key));
		}
		return res;
	}
	public void initTableData(MyHashMap<String, String> table,List<MyHashMap<String, Object>> data,String bussId,String taskId){
		MyHashMap<String, String> sub_table_info = new MyHashMap<String, String>();
		sub_table_info.put("tablekey",  table.get("table_key"));
		sub_table_info.put("tablename", table.get("table_name"));
		sub_table_info.put("detailkey",  table.get("detail_key"));
		sub_table_info.put("ismore",  table.get("ismore"));
		sub_table_info.put("refkey",  table.get("ref_key"));
		MyHashMap<String, Object> sub_data = getTableInfo(sub_table_info, bussId, taskId);
		if(sub_data!=null){
			data.add(sub_data);
		}
	}
	public MyHashMap<String, Object> getTableInfo(MyHashMap<String, String> main_table_info,String bussId,String taskId){
		Map<String, String> sqlMap = null;
		MyHashMap<String, String> tab = new MyHashMap<String, String>();
		String refKey = main_table_info.get("refkey");
		String tableKey = main_table_info.get("tablekey");
		String encrypt="1";
		//组织table公共信息
		tab.put(Contants.FORM_KEY_TABLE_NAME, tableKey);
		tab.put(Contants.FORM_KEY_TABLE_NAME_CH, main_table_info.get("tablename"));
		tab.put(Contants.FORM_KEY_TABLE_ISMORE,main_table_info.get("ismore"));
		if(OaActContants.COMM_TABLE_KEY.equals(tableKey)){
			encrypt = oaActExTableMapper.queryTableEncrypt(refKey);
		}else{
			encrypt = oaActExTableMapper.queryTableEncrypt(tableKey);
		}
		tab.put(OaActContants.FORM_ENCRYPT,encrypt);
		//taskId为空时、表示查询主表
		if(Validata.isNullOrEmpty(taskId)){
			List<MyHashMap<String, String>> act_data = actExDataMapper.queryActExDataByBussId(bussId);
			if(act_data!=null&&act_data.size()>0){
				tab.putAll(act_data.get(0));
			}
		}else{
			List<MyHashMap<String, String>> act_data_follow = actExDataFollowMapper.queryActExDataFollowWithBussIdAndTaskId(bussId, taskId);
			if(act_data_follow!=null&&act_data_follow.size()>0){
				tab.putAll(act_data_follow.get(0));
			}
		}
		//组织form字段信息
		List<MyHashMap<String, String>> cols = new ArrayList<MyHashMap<String,String>>();
		List<MyHashMap<String, String>> table_cols = actExBussDefMapper.queryDeatilsCols(main_table_info.get("detailkey"),main_table_info.get("tablekey"));
		String pkName = "";
		boolean isSubTab = Validata.notNullOrEmpty(taskId);
		for (MyHashMap<String, String> col:table_cols) {
			boolean isfk = Contants.BASE_STATE.equals(col.get("is_fk"));
			boolean ispk = Contants.BASE_STATE.equals(col.get("is_pk"));
			if(ispk){
				pkName = !isSubTab ? col.get("col_name"):pkName;
				tab.put(OaActContants.FORM_KEY_PKNAME, col.get("col_name"));
			}
			if(isfk){
				pkName = isSubTab ? col.get("col_name") : pkName;
				tab.put(OaActContants.FORM_KEY_FKNAME, col.get("col_name"));
			}
			if(!isfk){//外键字段不显示
				if(isSubTab && ispk){//子表的主键字段不显示
						continue;
				}else{
					MyHashMap<String, String> col_map = new MyHashMap<String, String>();
					col_map.put("colname", col.get("col_name").toLowerCase());
					col_map.put("colnamech", col.get("col_name_ch"));
					col_map.put("showtype", col.get("show_type"));
					col_map.put("ispk", col.get("is_pk"));
					col_map.put("isfk", col.get("is_fk"));
					cols.add(col_map);
				}
			}
		}
		if(Validata.isNullOrEmpty(taskId)){
			sqlMap = OaActivitiFormDataTool.getSelectSql(main_table_info.get("tablekey"), pkName, table_cols, bussId,null);
		}else{
			sqlMap = OaActivitiFormDataTool.getSelectSql(main_table_info.get("tablekey"), pkName, table_cols, bussId,taskId);
		}
		//获取form数据信息
		List<Map<?,?>> cols_list = sqlAdapterMapper.getDataBysql(sqlMap);

		MyHashMap<String, Object> res = new MyHashMap<String, Object>();
		res.put(Contants.FORM_KEY_TAB, tab);
		res.put(Contants.FORM_KEY_COLS, cols);
		res.put(Contants.FORM_KEY_DATA_SQL, sqlMap);
		if(cols_list == null || cols_list.size() == 0 || cols_list.get(0) == null){
			cols_list = new ArrayList<>();
		}
		res.put(Contants.FORM_KEY_DATA, cols_list);
		return res;
	}
	@Override
	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public int updateProgressToEnd(String processKey,String businessId,String endSign) throws Exception {
		// 将当前流程生成静态页面，并保存到历史表
		String path = saveProcessHistory(processKey,businessId);
		return actExDataMapper.updateProcessToEnd(businessId, (endSign==null||"".equals(endSign))?Contants.PROCESS_STATUS_END:endSign,path);
	}

	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public String saveProcessHistory(String processKey,String businessId) throws Exception{
		MyHashMap<String, Object> temp = null;
		MyHashMap<String, String> map = null;
		Entry<String, String> entry = null;
		//查询流程节点对应的表单数据
		List<MyHashMap<String, Object>> content = new ArrayList<MyHashMap<String, Object>>();
		List<MyHashMap<String, String>> list = actExDataFollowMapper.queryActExDataEndFollow(businessId);
		if(list!=null){
			String taskId;
			for(int i=0,j=list.size();i<j;i++){
				map = list.get(i);
				taskId = map.get("taskid");
				if(Validata.notNullOrEmpty(taskId)){
					if("转交".equals(map.get("action"))){
						temp = new MyHashMap<String, Object>();
					}else{
						temp = queryOriginalBussInfo(processKey,map.get("processnodeid"),businessId,map.get("taskid"));
					}
				}else{
					temp = new MyHashMap<String, Object>();
				}
				if(temp!=null){
					Iterator<Entry<String, String>> it = map.entrySet().iterator();
					while (it.hasNext()) {
						entry = it.next();
						temp.put(entry.getKey(), entry.getValue());
					}
					content.add(temp);
				}
			}
			temp = null;
			map = null;
			entry = null;
			list = null;
		}
		//创建 流程ID对应json文件上传到FTP 服务器 返回请求链接
		File file = null;
		try{
			Result res = new Result();
			res.setCode(0);
			//将流程唯一编码放入MsgId
			if(content!=null&&!content.isEmpty()){
				content.get(0).put("businessId", businessId);
			}
			res.setData(content);
			String fileName = new StringBuilder(businessId).append(".json").toString();
			String ftppath = StringUtil.getDate("/yyyy/MM/dd/");
			FreeMarkerUtil fm = new FreeMarkerUtil(ActProgressTableServiceImpl.class.getClassLoader().getResource("/").getPath()+"com/vito/act/service/impl/ftl");
			Map<String, String> data = new HashMap<String, String>();
			data.put("json", JSONUtil.converObject2String(res));
			fm.createFile("activitiData.ftl", data, fileName);
			file = new File(fileName);
			if(new FtpHelper().upload(file, fileName, ftppath)){
				return new StringBuilder(Contants.FTP_DOWNLOAD_URL_PREFIX).append("/").append(ftppath.replace("/", "_")).append(fileName).toString();
			}
			throw new IOException("ftp文件上传失败！");
		}finally{
			if(file!=null&&file.exists())
				file.delete();
			file = null;
		}
	}
	@Override
	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public int updateInstanceByBussId(String businessId, String instanceId) {
		return actExDataMapper.updateInstanceIdByBussId(businessId, instanceId);
	}
	/**
	 * 根据流程key、节点key、业务ID，查询主表及从表表名
	 * @param processKey
	 * @param bussId
	 * @return
	 */
	@Override
	public List<MyHashMap<String, String>> findProcessView(String processKey,String bussId){
		return actExDataFollowMapper.queryActExDataFollow(bussId);
	}
	/**
	 * @param businessId 业务编码
	 * @param processInstanceId 流程实例id
	 * @param isHangUp true挂起，false解挂
	 */
	@Override
	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public Result hangUp(UserModel user,String businessId,String processInstanceId, boolean isHangUp) {
		Result res = new Result();
		String currentUser = user.getUserId();
		try{
			if(!isHangUp){//解挂 校验当前登录用户是否为挂起用户
				boolean hangFlag = false;
				List<MyHashMap<String, String>> list = actExDataMapper.queryActExDataByBussId(businessId);
				if(list.size()>0){
					for (int i = 0; i < list.size(); i++) {
						MyHashMap<String, String> map = list.get(i);
						if(map.get("hangupuserid")!=null&&!"".equals(map.get("hangupuserid").trim())){
							if(currentUser.equals(map.get("hangupuserid"))){//解挂权限校验
								hangFlag=true;
								break;

							}
						}
					}

				}
				if(hangFlag){
					// 调用挂起结果方法
					ActivitiTool.hangUp(processInstanceId, isHangUp);
					actExDataMapper.updateProgressToHungupEnd(businessId, currentUser, Contants.PROCESS_STATUS_IN);
					res.setCode(Result.CODE_OK);
				}else{
					res.setCode(Result.CODE_NO_RIGHT);
					res.setMsg("您不是挂起人，无权解挂该审批单");
				}
			}else{
				// 调用挂起结果方法
				ActivitiTool.hangUp(processInstanceId, isHangUp);
				actExDataMapper.updateProgressToHungup(businessId, currentUser, Contants.PROCESS_STATUS_HANGUP);
				res.setCode(Result.CODE_OK);
			}
		}catch(Exception e){
			res.setCode(Result.CODE_ERROR);
			e.printStackTrace();
		}
		return res;
	}
	@Override
	@CacheEvict(value=CACHE_ACT_VALUE,allEntries=true)
	public Result endProcess(UserModel user,Map<String, Map<String, Object>> data) {
		Result res = new Result();
		try{
			Map<String, Object> table = actExTableColsService.getTablePkAndFks(ActivitiFormDataTool.getTableData(data));
			ActivitiFormDataTool.generateTabkeKey(table, data,user);
			if(saveProgressTableInfo(user,data,ProcessButtonEnum.END)>0){
				Map<String, Object> info = data.get(Contants.FORM_KEY_INFO);
				String taskId = (String)info.get(Contants.FORM_KEY_TASKID);
				String businessId = (String)info.get(Contants.FORM_KEY_BUSENESSID);
				TaskService taskService  = ActivitiTool.getTaskService();
				Integer endInstances = (Integer)taskService.getVariable(taskId, OaActContants.VARIABLES_END_INSTANCES);
				if(endInstances != null){
					endInstances ++;
				}else{
					endInstances = 0;
				}
				Map<String, Object> variables = new HashMap<String, Object>();
				variables.put(OaActContants.VARIABLES_END_INSTANCES, endInstances);
				variables.put(OaActContants.ENDPROCESS_KEY, OaActContants.ENDPROCESS_STATUS);
				Task t =taskService.createTaskQuery().taskAssignee(user.getUserId()).taskId(taskId).singleResult();
				String nodeId = t.getTaskDefinitionKey();
				//修改节点审批状态:已审批
				BusinessApproverModel currentAssignee = oaActApproverMapper.queryaCurrentApprover(businessId,nodeId);
				if(currentAssignee != null){
					currentAssignee.setApproveStatus(OaActContants.APPROVE_STATUS_APPROVED);
					oaActApproverMapper.updateApproveStatus(currentAssignee);
				}
				ActivitiTool.endProcess(taskId,variables);
				res.setCode(Result.CODE_OK);
			}else{
				res.setCode(Result.CODE_ERROR);
			}
		}catch(Exception e){
			res.setCode(Result.CODE_ERROR);
			e.printStackTrace();
		}
		return res;
	}
	@Override
	public List<MyHashMap<String, String>> queryBussNeedCols(String processKey,String processNodeId) {
		return actExBussDefMapper.queryBussNeedCols(processKey, processNodeId);
	}
	/**
	 * 根据流程key、节点key、业务ID，查询主表及从表表名
	 * @param processKey
	 * @param bussId
	 * @return
	 */
	@Override
	public List<MyHashMap<String, String>> findProcessData(String processKey,String bussId){
		String tableName = "";
		boolean firstNodeHasFollowTable = false;
		//查询首节点
		List<MyHashMap<String, String>> firstNodeTables = actExBussDefMapper.queryProcessNodeTables(processKey, Contants.FORM_PROCESS_START);
		if(firstNodeTables!=null&&firstNodeTables.size()>0){
			//确定主表
			for (MyHashMap<String, String> map:firstNodeTables) {
				//主表
				if(Validata.isNullOrEmpty(map.get("parent_table_key"))){
					tableName = map.get("table_key");
				}
			}
			//判断首节点是否有从表
			for (MyHashMap<String, String> map:firstNodeTables) {
				//主表
				if(!Validata.isNullOrEmpty(map.get("parent_table_key")) && map.get("parent_table_key").equals(tableName)){
					firstNodeHasFollowTable = true;
					break;
				}
			}
		}
		//首节点有从表
		if(firstNodeHasFollowTable){
			List<MyHashMap<String, String>> list = actExDataFollowMapper.queryActExDataFollow(bussId);
			list.addAll(actExDataFollowMapper.queryActExDataNowFollow(bussId));
			return list;
		}else{
			List<MyHashMap<String, String>> list = actExDataMapper.queryActExData(Contants.FORM_PROCESS_START, processKey, Contants.FORM_PROCESS_MAIN_TASKID, bussId);
			if(list!=null&&list.size()>0){
				list.get(0).put("action", "提交");
			}
			list.addAll(actExDataFollowMapper.queryActExDataFollow(bussId));
			list.addAll(actExDataFollowMapper.queryActExDataNowFollow(bussId));
			return list;
		}
	}
	@Override
	public Map<String, Object> queryOverInfoSingle(String url){
		String path= url.substring(url.lastIndexOf("/")+1);
		path = path.substring(0,path.lastIndexOf("_")+1).replace("_", "/");
		path = path.substring(1,path.length());
		String fileName = url.substring(url.lastIndexOf("/")+1);
		fileName = fileName.substring(fileName.lastIndexOf("_")+ 1);
		FtpModel ftp = new FtpModel();
		ftp.setFilePath(path);
		ftp.setFileNewName(fileName);
		List<FtpModel> ftpList = new ArrayList<FtpModel>();
		ftpList.add(ftp);
		List<Map<String, Object>> datas = queryOverInfo(ftpList);
		if(!datas.isEmpty()){
			return datas.get(0);
		}else{
			return null;
		}
	}
	@Override
	public List<Map<String, Object>> queryOverInfoList(List<FtpModel> ftps){
		return queryOverInfo(ftps);
	}
	@SuppressWarnings("unchecked")
	private List<Map<String, Object>> queryOverInfo(List<FtpModel> ftps){
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		Map<String,StringBuffer> formMap= readFileStream(ftps);
		for(FtpModel ftp: ftps){
			String name = ftp.getFileNewName();
			StringBuffer formStr = formMap.get(name);
			Map<String,Object> data= null;
			if(formStr != null && formStr.length()>0){
				data = JSON.parseObject(formStr.toString(), Map.class);
				//解析数据（存在需要解密的数据）
				List<Map<String,Object>> list = (List<Map<String, Object>>) data.get(Contants.FORM_KEY_DATA);
				List<Map<String, Object>> mains = null;
				List<Map<String, Object>> subs = null;
				for(Map<String,Object> item : list){
					mains = (List<Map<String, Object>>) item.get(Contants.FORM_KEY_MAIN);
					subs = (List<Map<String, Object>>) item.get(Contants.FORM_KEY_SUBS);
					if(mains != null){
						for(Map<String, Object> main:mains){
							decryptFormData(main);
						}
					}
					if(subs != null){
						for(Map<String, Object> sub:subs){
							decryptFormData(sub);
						}
					}
				}
			}
			if(data != null){
				result.add(data);
			}
		}
		return result;
	}
	@Autowired
	private OaActivitiFormDataTool formDataTool;
	/**
	 * 池中所保存的线程数，包括空闲线程。
	 */
	private final static int CORE_POOL_SIZE = 5;
	/**
	 * 池中允许的最大线程数。
	 */
	private final static int MAXI_MUM_POOL_SIZE = 10;
	/**
	 * 当线程数大于核心线程时，此为终止前多余的空闲线程等待新任务的最长时间
	 */
	private final static long KEEP_ALIVE_TIME = 30;
	/**
	 * 执行前用于保持任务的队列5，即任务缓存队列
	 */
	private final static LinkedBlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<Runnable>();
	private final static ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXI_MUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MINUTES, WORK_QUEUE);
	/**
	 * 从FTP下载完结流程表单列表数据
	 * @param listFtpModel
	 * @return
	 * @throws IOException
	 * @throws ParamErrorException
	 */
	public  Map<String,StringBuffer> readFileStream(List<FtpModel> listFtpModel){
		final StringBuffer runTimes = new StringBuffer();
		final Map<String,StringBuffer> contentMap = new Hashtable<String,StringBuffer>();
		for(final FtpModel ftpModel : listFtpModel){
			THREAD_POOL_EXECUTOR.execute(new Runnable() {
				@Override
			    public void run() {
			        try {
			            StringBuffer sb = formDataTool.readFileStream(ftpModel);
			            contentMap.put(ftpModel.getFileNewName(),sb);
			        } finally{
			        	/*StringBuffer是线程安全的，所以不需要加锁*/
			        	runTimes.append('0');
			        }
			    }
			});
		}

		while(true){
			try {
				if(listFtpModel.size() == runTimes.length()){
					break;
				}
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		return contentMap;
	}
}
